/*
 * Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.cloudphone.utils;

import com.huawei.cloudphone.common.CASLog;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public final class CasAESUtils {

    // 日志标签
    private static final String TAG = "CasAESUtils";

    // 字符串编码格式UTF-8
    private static final String CHARSET_UTF8 = "UTF-8";

    // AES加密的密钥长度值
    private static final int SECRET_KET_LENGTH = 16;

    /**
     * ASE加密
     *
     * @param sSrc      原生
     * @param hexAesKey 秘钥
     * @param hexIv     IV值
     * @return 密文
     */
    public static String encryptWithAESGCM(String sSrc, String hexAesKey, String hexIv) {
        if (null == hexAesKey || hexAesKey.length() == 0) {
            return "";
        }

        if (null == hexIv || hexIv.length() == 0) {
            return "";
        }

        byte[] sKey = hexToByteArray(hexAesKey);
        if (sKey == null || sKey.length != SECRET_KET_LENGTH) {
            CASLog.w(TAG, "encryptWithAESGCM aes key length illegal.");
            return "";
        }

        // 还原盐值的byte
        byte[] iv = hexToByteArray(hexIv);

        try {
            SecretKeySpec secretKeySpec = new SecretKeySpec(sKey, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            // 需要一个向量iv，可增加加密算法的强度
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

            byte[] encrypted = cipher.doFinal(sSrc.getBytes(CHARSET_UTF8));
            return bytesToHex(encrypted);
        } catch (Exception e) {
            CASLog.e(TAG, "AESBaseEncrypt Exception", e);
        }
        return "";
    }

    /**
     * AES解密
     *
     * @param sSrc      加密内容
     * @param hexAesKey 秘钥
     * @param hexIv     盐值
     * @return
     */
    public static String decryptWithAESGCM(String sSrc, String hexAesKey, String hexIv) {
        if (null == hexAesKey || hexAesKey.length() == 0) {
            return "";
        }

        if (null == hexIv || hexIv.length() == 0) {
            return "";
        }

        byte[] sKey = hexToByteArray(hexAesKey);

        // 判断Key是否为16位
        if (sKey == null || sKey.length != SECRET_KET_LENGTH) {
            CASLog.w(TAG, "decryptWithAESGCM aes key length illegal.");
            return "";
        }

        byte[] iv = hexToByteArray(hexIv);

        try {
            SecretKeySpec sKeySpec = new SecretKeySpec(sKey, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); // 需要一个向量iv，可增加加密算法的强度

            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, ivParameterSpec);
            byte[] srcByte = hexToByteArray(sSrc);
            byte[] original = cipher.doFinal(srcByte);
            return new String(original, CHARSET_UTF8);
        } catch (Exception e) {
            CASLog.e(TAG, "AESBaseDecrypt error", e);
        }
        return "";
    }

    /**
     * 获取十六进制的盐值
     *
     * @return 盐值
     */
    public static String getHexSalt() {
        SecureRandom random = CasSecurityUtil.drbg();
        byte[] bytes = new byte[SECRET_KET_LENGTH];
        random.nextBytes(bytes);
        return bytesToHex(bytes);
    }

    /**
     * 字节数组转16进制
     *
     * @param bytes 需要转换的byte数组
     * @return 转换后的Hex字符串
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() < 2) {
                sb.append(0);
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    /**
     * 十六进制文本转byte
     *
     * @param inHex 十六进制
     * @return byte数组
     */
    public static byte[] hexToByteArray(String inHex) {
        int hexLen = inHex.length();
        byte[] result;
        if ((hexLen & 1) == 1) {
            // 奇数
            hexLen++;
            result = new byte[(hexLen / 2)];
            inHex = "0" + inHex;
        } else {
            // 偶数
            result = new byte[(hexLen / 2)];
        }
        int index = 0;
        for (int position = 0; position < hexLen; position += 2) {
            result[index] = hexToByte(inHex.substring(position, position + 2));
            index++;
        }
        return result;
    }

    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    private static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }
}
